package com.uinnova.product.eam.init.cassso;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.uinnova.product.eam.service.CasLoginService;
import com.uinnova.project.base.diagram.exception.LoginFailException;
import com.uino.api.client.permission.IOauthApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.OauthResourceDetail;
import com.uino.bean.permission.business.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: CAS单点登录过滤器
 * @author: LiMG
 * @create: 2024-05-24 14:40:39
 **/
@WebFilter(urlPatterns = "/*")
@Component
@Order(1)
@Slf4j
@ConditionalOnProperty(name = "monet.login.loginMethod", havingValue = "guotouiam")
public class CASLoginFilter implements Filter {

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Value("${server.servlet.context-path:/}")
    private String contextPath;

    @Autowired
    private IOauthApiSvc oauthApiSvc;

    @Autowired
    private CasLoginService casLoginService;

    @Autowired
    private IUserApiSvc userApiSvc;

    {
        log.info("========================================");
        log.info("CAS单点登录过滤器初始化成功");
        log.info("========================================");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 获取当前请求url
        String requestUri = request.getRequestURI();
        log.info("===requestUri-1=== " + requestUri);
        requestUri = StrUtil.sub(requestUri, requestUri.indexOf(contextPath) + contextPath.length(), requestUri.length());
        log.info("===requestUri-2=== " + requestUri);
        // 获取uino_oauth_resource.json配置文件中需要排除过滤的url
        OauthResourceDetail resourceDetail = oauthApiSvc.getResourceDetail(contextPath.replace("/", ""));
        // 需要校验的url
        String checkUri = requestUri;
        List<String> permitAllUrls = resourceDetail.getPermitAllUrls();
        log.info("===permitAllUrls=== " + permitAllUrls);
        // 临时处理免登录配置时效问题
        List<String> interfaceUrl = new ArrayList<>(Arrays.asList("/interface/assetList","/interface/diagramJson","/interface/projectSave","/interface/projectQuery"));
        boolean isInterface = interfaceUrl.contains(requestUri);
        // 判断当前url是否需要排除过滤
        boolean isPermitFlag = permitAllUrls
                .stream()
                .anyMatch(permitUrl -> ReUtil.isMatch(permitUrl.trim(), checkUri));
        // 获取authorization
        String authorization = request.getHeader(Header.AUTHORIZATION.getValue());
        if (isPermitFlag || isInterface) {
            // 如果需要排除过滤，则设置header中的authorization到request中并继续
            if (!StrUtil.isEmpty(authorization)) {
                request.setAttribute("authorization", authorization.substring("Bearer ".length()));
            }
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        Cookie[] cookies = request.getCookies();
        if (null == cookies) {
            resolver.resolveException(request, response, null, new LoginFailException("登录凭证已过期"));
            return;
        }
        if (cookies != null) {
            List<Cookie> iamToken = Arrays.stream(cookies).filter(item -> item.getName().equals("IAMToken")).collect(Collectors.toList());
            if (iamToken.size() != 0) {
                authorization = "Bearer " + iamToken.get(0).getValue();
            }
        }
        // 没有携带access_token则直接跳转登录页面
        if (StrUtil.isEmpty(authorization)) {
            resolver.resolveException(request, response, null, new LoginFailException("登录凭证已过期，请重新登录"));
        } else {
            Object user = casLoginService.getUser(authorization);
            if (null == user) {
                // 用户为空，从国投IAM系统中获取
                JSONObject result = casLoginService.getUserInfo(authorization);
                if (result.getInteger("code") == 0) {
                    // 票据验证成功
                    String account = result.getString("account");
                    try {
                        UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(account);
                        // 存入redis
                        casLoginService.setUser(userInfo, authorization);
                        request.setAttribute("authorization", authorization.substring("Bearer ".length()));
                        filterChain.doFilter(servletRequest, servletResponse);
                    } catch (Exception e) {
                        // 未找到用户
                        log.error("该用户在ea系统未查询到: {}", e.getMessage(), e);
                        throw new BinaryException("该用户在ea系统未查询到，请联系管理员同步用户数据");
                    }
                } else {
                    // 票据验证失败
                    /**
                     * accesstoken非法或过期，重定向登录页面
                     */
                    resolver.resolveException(request, response, null, new LoginFailException("登录凭证已过期，请重新登录"));
                }
            } else {
                request.setAttribute("authorization", authorization.substring("Bearer ".length()));
                filterChain.doFilter(servletRequest, servletResponse);
            }
        }
    }

}
